home *** CD-ROM | disk | FTP | other *** search
- //
- // str.cpp : str class implementation
- // Author : Roy S. Woll
- //
- // Copyright (c) 1993 by Roy S. Woll
- // You may distribute this source freely as long as you leave all files
- // in their original form, including the copyright notice as is.
- //
- //
- // Version 2.11 3/17/93
- // Friend operator ">>" changed to use str's buffer if > 256.
- // Assign operator optimized to not copy referenced data.
- // Fix - Remove member function now transfers only necessary characters
- //
- // Version 2.00 12/5/92
- // Support searching/replacing, regular expressions, case sensitivity
- //
- // Fixed the following bugs.
- // 1. Fixed size strings
- // 2. Concatenating a substr
- //
- // Changed member functions pad/strip to modify instance, and introduced
- // friend functions pad/strip.
- //
- // Version 1.00 10/20/92
- //
- #include <ctype.h>
- #include <string.h>
- #include <iostream.h>
- #include <iomanip.h>
- #include <assert.h>
-
- #include "str.h"
- #include "dynstream.h"
-
- int strnicmp(const char * s1, const char * s2, unsigned n);
- int stricmp(const char * s1, const char * s2);
- char * strlwr(char *);
- char * strupr(char *);
-
- inline int min(int x, int y){if (x<y) return x; else return y;}
- inline int max(int x, int y){if (x>y) return x; else return y;}
-
- // Define macro used to adjust internal debugging counters for object
- #ifdef DEBUG_STR
- #define STR_SUB_COUNTERS(count) count--;
- #define STR_ADD_COUNTERS(count) count++;Total##count++;
- #else
- #define STR_SUB_COUNTERS(count)
- #define STR_ADD_COUNTERS(count)
- #endif
-
-
- static str::strdata NullData = {0, 0, 1, 0, 1, ""};
-
- // Create and map to new buffer, and if previous buffer exists,
- // transfer to new buffer.
- // Delete old buffer if unreferenced.
- char * str::getNewBuffer(int newbufsize){
- return getNewBuffer(length(), newbufsize);
- };
-
- char * str::getNewBuffer(int len, int newbufsize)
- {
- if (data==&NullData){
- if (memsize_incr) newbufsize = max(newbufsize, memsize_init);
- else newbufsize = memsize_init;
- }
- else {
- if (!memsize_incr) return NULL;
- if ((newbufsize>data->cursize) || (!newbufsize) )
- newbufsize = max(newbufsize, data->cursize + memsize_incr);
- else newbufsize = max(newbufsize, memsize_init);
- }
- if (!newbufsize) newbufsize = memsize_incr; // don't allow 0 size
-
- strdata * newdata;
- init(newdata, newbufsize, 0);
- setNewBuffer(newdata, newbufsize, len);
-
- return data->buf;
- };
-
- // Map to new buffer and if previous buffer exists, transfer to new buffer
- void str::setNewBuffer(strdata * newdata,
- int newbufsize, int len){
-
- newdata->curlength = data->curlength;
- newdata->strChange = data->strChange;
-
-
- if (data->mystream) {
-
- // Use existing stream
- newdata->mystream = data->mystream;
-
- // update existing stream to map to new buffer
- newdata->mystream->rdbuf()->setNewBuffer(newdata->buf, newbufsize);
-
- // update stream length next time stream is called for previous data
- if (!data->strChange){
- data->strChange = 1;
- data->curlength = data->mystream->rdbuf()->out_waiting();
- };
-
- // force previous data to have unitialized stream
- data->mystream = NULL;
- };
-
- memcpy(newdata->buf, data->buf, len);
-
- if (!(--data->refcount)) {
- delete data;
- STR_SUB_COUNTERS(AllocationCount)
- }
-
-
- data = newdata;
- };
-
-
- void str::init(strdata*& adata, int cursize,
- int curlength)
- {
- STR_ADD_COUNTERS(AllocationCount)
- if (!cursize) cursize=STR_DEFAULT_MEMINCR;
-
- adata =
- (strdata *) new char [(cursize+1)+
- sizeof(strdata)-strdata::STR_DEBUG_BUFSIZE];
- if (!adata){
- cout << "Failed to allocate memory (" << cursize << ")" << endl;
- assert(adata);
- };
-
- adata->cursize=cursize;
- adata->curlength=curlength;
- adata->refcount=1;
- adata->mystream=NULL;
- adata->strChange=1;
- };
-
-
- // Construct an empty str
- str::str (void):
- data(&NullData),
- memsize_init(0), memsize_incr(STR_DEFAULT_MEMINCR),
- flags(defaultFlags)
- {
- STR_ADD_COUNTERS(ObjectCount)
- data->refcount++;
- };
-
- // Construct an empty str
- str::str (int p_bufsize, int p_incr):
- data(&NullData),
- memsize_init(p_bufsize), memsize_incr(p_incr),
- flags(defaultFlags)
- {
- STR_ADD_COUNTERS(ObjectCount)
- data->refcount++;
- };
-
-
- // Construct a str containing substr, char *
- str::str (const char * s1, const char * s2):
- memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
- flags(defaultFlags)
- {
-
- STR_ADD_COUNTERS(ObjectCount)
- int len1=(s1 ? strlen(s1) : 0);
- int len2=(s2 ? strlen(s2) : 0);
-
- init(data, len1+len2, len1+len2);
- memcpy(data->buf, s1, len1);
- memcpy(data->buf+len1, s2, len2);
- };
-
- // Construct a str containing char *, substr
- str::str (const char * s1, const substr& s2):
- memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
- flags(defaultFlags)
- {
-
- STR_ADD_COUNTERS(ObjectCount)
- int len1=(s1 ? strlen(s1) : 0);
- int len2=s2.length();
-
- init(data, len1+len2, len1+len2);
- memcpy(data->buf, s1, len1);
- memcpy(data->buf+len1, &s2.mystr->data->buf[s2.posReplace], len2);
- };
-
- // Construct a str containing two char *
- str::str (const substr& s1, const char * s2):
- memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
- flags(defaultFlags)
- {
-
- STR_ADD_COUNTERS(ObjectCount)
- int len1= s1.length();
- int len2= (s2 ? strlen(s2) : 0);
-
- init(data, len1+len2, len1+len2);
- memcpy(data->buf, &s1.mystr->data->buf[s1.posReplace], len1);
- memcpy(data->buf+len1, s2, len2);
- };
-
- // Construct a str containing two substr
- str::str (const substr& s1, const substr& s2):
- memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
- flags(defaultFlags)
- {
-
- STR_ADD_COUNTERS(ObjectCount)
- int len1= s1.length();
- int len2= s2.length();
-
- init(data, len1+len2, len1+len2);
- memcpy(data->buf, &s1.mystr->data->buf[s1.posReplace], len1);
- memcpy(data->buf+len1, &s2.mystr->data->buf[s2.posReplace], len2);
- };
-
- // Construct a str containing char *
- str::str (const char * s, int p_bufsize, int p_incr):
- memsize_init(p_bufsize),memsize_incr(p_incr),
- flags(defaultFlags)
- {
- STR_ADD_COUNTERS(ObjectCount)
- if (!s) return;
-
- int curlength, cursize;
-
- if (memsize_incr==0) { // not allowed to expand
- curlength = min(strlen(s), memsize_init);
- cursize = memsize_init;
- }
- else {
- curlength=strlen(s);
- cursize = max(curlength, memsize_init);
- };
-
- init(data, cursize, curlength);
- memcpy(data->buf, s, curlength);
- };
-
- // Construct a str containing str
- str::str (const str& s, int p_bufsize, int p_incr):
- memsize_init(p_bufsize),memsize_incr(p_incr),
- flags(defaultFlags)
- {
- STR_ADD_COUNTERS(ObjectCount)
-
- if (memsize_incr) {
- data = s.data;
- data->refcount++;
- }
- else {
- int curlength = min(s.length(), memsize_init);
- init(data, memsize_init, curlength);
- memcpy(data->buf, s, curlength);
- };
-
- };
-
-
- // Return a ostream that maps to the same buffer as the str
- ostream& str::stream(int pos){
- return stream().seekp(pos);
- };
-
- // Return a ostream that maps to the same buffer as the str
- ostream& str::stream(void){
-
- //
- // check if need to allocate more memory
- //
- int allocsize=0;
- if (data==&NullData) allocsize = memsize_init; // first time allocating
- else if (length()>=size()) allocsize = size()+memsize_incr;
- _checkMemAllocation(allocsize);
-
- //
- // Create stream if it doesn't exist
- // otherwise tell dynstream about me in case it needs to extend buf
- //
- if (!data->mystream) data->mystream = new dynstream(this);
- else data->mystream->rdbuf()->set_str(this);
-
-
- //
- // update stream length if length has been changed by str operators.
- // Not done every time in case stream operation was the last operation
- // to change the length.
- //
- if (data->strChange) {
- data->mystream->rdbuf()->set_len(data->curlength);
- data->strChange=0;
- };
- return *data->mystream;
- };
-
- int str::length(void) const{
- if ((!data->strChange) && (data->mystream))
- setlength(data->mystream->rdbuf()->out_waiting());
-
- return data->curlength;
- };
-
- str::~str (void){
- STR_SUB_COUNTERS(ObjectCount)
-
- if (!(--data->refcount)){
- STR_SUB_COUNTERS(AllocationCount)
-
- delete data->mystream;
- delete data;
- };
- };
-
- //
- // return (const char *)
- //
- str::operator const char * () const{
- data->buf[length()] = 0;
- return data->buf;
- };
-
- const char * str::operator()(int index) const
- {
- return (*this)() + index;
- }
-
- char& str::operator[](int position) // array indexing
- {
- if (data->refcount>1) getNewBuffer(data->cursize);
-
- #ifndef SMART_STR_USER
- //
- // Force string to be null-terminated in case user
- // uses the "&" operator to pass a pointer (ie. &mystr[3])
- //
- if (!data->strChange) return *(char *)(*this)(position);
-
- #endif
-
-
- return data->buf[position];
- }
-
- int str::size(void) const{
- return data->cursize;
- };
-
- //
- // str member = operators
- //
- str & str::_assign(const char * s, int len)
- {
- // Get new buffer if necessary, but don't transfer contents.
- // This is handled specially, so as to remove the unnecessary transfer.
- if ((data->refcount>1) || (size()<len))
- getNewBuffer( 0, max(size(),len) );
-
- if (!memsize_incr) len = min(len, size());
- memcpy(data->buf, s, len);
- setlength(len);
- return *this;
-
- };
-
- str& str::operator = (const str& s){
- if (this == &s) return *this; // assignment to self
- if (data == s.data) return *this; // assignment to self
-
- if (!memsize_incr) return _assign(s, s.length());
-
- dynstream * prevStream=NULL;
-
- if (!(--data->refcount)) { // deallocate old pointer
- STR_SUB_COUNTERS(AllocationCount)
-
- //
- // try to reuse this stream
- //
- prevStream = data->mystream;
- if (s.data){
- if (s.data->mystream) {
- delete data->mystream;
- prevStream = NULL;
- }
- }
-
- delete data;
- };
-
- data = s.data;
-
- data->refcount++;
-
- //
- // Map my stream to point to an existing stream using buffer data->buf
- //
- if (prevStream) {
-
- data->mystream = prevStream; // what about previous mystream?
-
- //
- // update s stream to map to new this stream
- //
- data->mystream->rdbuf()->setNewBuffer(data->buf, size());
-
- //
- // update stream length next time stream is called for previous data
- //
- data->strChange = 1;
-
- }
-
-
- return *this;
-
- };
-
-
- str& str::operator = (const substr& s){
- return _assign((*s.mystr)(s.posReplace), s.numReplace);
- };
-
- str& str::operator = (const char * s){
- return _assign(s, strlen(s));
- };
-
- str& str::assign(const char * s, int len){
- return _assign(s, min(strlen(s), len));
- };
-
- str& str::operator = (const char s){
- return _assign(&s, 1);
- };
-
- str & str::_concat(const char * s, int len)
- {
- int mylen = length();
-
- _checkMemAllocation(mylen + len);
-
- if (!memsize_incr) len = min(len, size()-mylen);
- memcpy(data->buf + mylen, s, len); //concat
- setlength(mylen+len);
- return *this;
-
- };
-
-
- //
- // str member += operators
- //
- str & str::operator += (const str& s){
- if (!length()) return *this=s;
- return _concat(s, s.length());
- };
-
- str & str::operator += (const substr& s){
- return _concat(&s.mystr->data->buf[s.posReplace], s.length());
- };
-
- str & str::operator += (const char * s){
- return _concat(s, strlen(s));
- };
-
- str & str::operator += (const char s){
- return _concat(&s, 1);
- };
-
-
- //
- // str member << operators
- //
- str& str::operator << (const str& s) { return *this+=s;};
- str& str::operator << (const substr& s) { return *this+=s;};
- str& str::operator << (const char * s) { return *this+=s;};
- str& str::operator << (const char s) { return *this+=s;};
- str& str::operator << (const int s){
- stream() << s;
- return *this;
- };
-
- //
- // str member + operators
- //
- str str::operator+(const _SUBSTR & b) const{ return str(*this,b); };
- str str::operator+(const str&b) const{ return str(*this,b); };
- str str::operator+(const char * b) const{ return str(*this,b); };
- str str::operator+(const char b) const{
- char buf[2];
- buf[0]=b;
- buf[1]=0;
-
- return str(*this,buf);
- };
-
-
- //
- // istream/ostream friend functions
- //
- istream& operator >> (istream& stream, str & s){
- if (s.memsize_init>256){ // Use str's current data buffer
- s = " "; // Gets new buffer if neccessary (ie. reference)
- stream.getline(s.data->buf, s.size());
- s.setlength(stream.gcount());
- if (s[s.length()]==10) // retrieve to end of line
- s.setlength(s.length()-1);
- }
- else {
- char buf[256];
- stream.getline(buf, 256);
- if (buf[stream.gcount()-1]==10) // retrieve to end of line
- buf[stream.gcount()-1]=0;
-
- s = buf;
- };
-
- return stream;
- };
-
- ostream& operator << (ostream& stream, const str & s){
- return stream << s();
- };
-
-
- //
- // uppercase/lowercase friend functions
- //
- str uppercase(const char * s) {
- str newstr(s);
- strupr((char *)newstr());
- return newstr;
- };
-
- str lowercase(const char * s) {
- str newstr(s);
- strlwr((char *)newstr());
- return newstr;
- };
-
-
- //
- // pad/strip
- //
- str& str::pad(int padsize, PadStripT t, char padchar){
-
- int len = length();
-
- if (len<padsize) {
-
- _checkMemAllocation(padsize);
- if (!memsize_incr) padsize = min(padsize, size());
-
- if (t == right)
- memset(&data->buf[len], padchar, padsize-len);
-
- else if (t == both){
- int len1 = (padsize-len)/2;
- int len2 = (padsize-len+1)/2;
-
- memmove(&data->buf[len1], &data->buf, len);
- memset(&data->buf[0], padchar, len1);
- memset(&data->buf[len+len1], padchar, len2);
- }
-
- else{
- int len1 = (padsize-len);
-
- memmove(&data->buf[len1], &data->buf, len);
- memset(&data->buf[0], padchar, len1);
- }
-
- setlength(padsize);
- };
-
- return *this;
- }
-
- str& str::strip(PadStripT t, char stripchar){
-
- int len = length();
- int start = 0;
- int end = len-1;
-
- if (end<0) return *this;
-
- if ((t == leading) || (t==both)){
- for (; start<=end; start++)
- if (data->buf[start] != stripchar) break;
- };
-
- if ((t == trailing) || (t==both)){
- if (data->buf[end] == stripchar) {
- for (; end >= start; end--){
- if (data->buf[end] != stripchar) break;
- };
- };
- };
-
- if ((end-start+1)<len)
- {
- _checkMemAllocation();
- if (start) memmove(&data->buf[0], &data->buf[start], end-start+1);
- setlength(end-start+1);
- };
-
- return *this;
-
- };
-
-
- str& str::strip(PadStripT t, const char * stripchars){
-
- int len = length();
- int start = 0;
- int end = len-1;
-
- if (end<0) return *this;
-
-
- if ((t == leading) || (t==both)){
-
- int pos = strspn((*this)(), stripchars);
- if (pos>0) start += pos;
-
- };
-
- if ((t == trailing) || (t==both)){
-
- if (strchr(stripchars, data->buf[end])){
- for (; end>=start; end--){
- if (!strchr(stripchars, data->buf[end])) break;
- }
- }
- };
-
- if ((end-start+1)<len)
- {
- _checkMemAllocation();
- if (start) memmove(&data->buf[0], &data->buf[start], end-start+1);
- setlength(end-start+1);
- };
-
- return *this;
- };
-
- str pad(str s, int padsize, str::PadStripT t, char padchar){
- return s.pad(padsize, t, padchar);
- };
-
- str strip(str s, str::PadStripT t, const char * stripchars){
- return s.strip(t, stripchars);
- };
-
- str strip(str s, str::PadStripT t, char stripchar){
- return s.strip(t, stripchar);
- };
-
-
- //
- // insert/remove
- //
- int str::insert(int pos, char ch){
- char tempstr[2];
- tempstr[0] = ch;
- tempstr[1] = 0;
- return insert(pos, tempstr);
- }
-
- int str::insert(int pos, const char * insertStr){
- int len = length();
- int afterPos = len+1-pos; // number of characters following pos
-
- if (afterPos<0) return 0; // out of range
-
- int insertLen = strlen(insertStr);
- _checkMemAllocation( len+insertLen );
-
- if (!memsize_incr) insertLen = min(insertLen, size()-len);
-
- if (insertLen){
- if (afterPos)
- memmove(&data->buf[pos + insertLen], &data->buf[pos], afterPos);
- memmove(&data->buf[pos], insertStr, insertLen);
- setlength(len+insertLen);
- return 1;
- }
- else return 0;
- };
-
- void str::remove(int pos, int numdel){
- int len = length();
- if (pos>=len) return;
- _checkMemAllocation();
-
- numdel = min(numdel, len-pos);
- memmove(&data->buf[pos], &data->buf[pos+numdel], len-(numdel+pos));
- setlength(len-numdel);
- };
-
-
- //
- // substr member operators/functions
- //
- _SUBSTR::substr(const str * data, int AposReplace, int AnumReplace):
- mystr((str *)data), posReplace(AposReplace), numReplace(AnumReplace){};
-
- _SUBSTR str::operator()(int pos, int numreplace)
- {
- return substr(this, pos, numreplace);
- }
-
- const _SUBSTR str::operator()(int pos, int numreplace) const
- {
- return substr(this, pos, numreplace);
- }
-
- int _SUBSTR::length(void) const{
- return min(numReplace, max(0, mystr->length()-posReplace) );
- };
-
-
- str & _SUBSTR::operator = (const char * s){
- if (posReplace<0) return *this->mystr;
-
- if (strlen(s)==length()){
- mystr->_checkMemAllocation();
- memcpy(&mystr->data->buf[posReplace], s, length());
- }
- else {
- mystr->remove(posReplace, numReplace);
- mystr->insert(posReplace, s);
- };
- return *this->mystr;
- };
-
- str & _SUBSTR::operator = (const substr& s){
- return *this = *s.mystr;
- };
-
- str _SUBSTR::operator+(const char * s) const{
- return str(*this, s);
- };
-
- str _SUBSTR::operator+(const substr& s) const{
- return str(*this, s);
- };
-
- int _SUBSTR::compare(const char * s) const{
- return mystr->strncmp((*this->mystr)(posReplace), s, numReplace);
- };
-
- int _SUBSTR::compare(const substr& s) const{
- int len = min(numReplace, s.numReplace);
- return mystr->strncmp((*this->mystr)(posReplace), (*s.mystr)(s.posReplace), len);
- };
-
- int _SUBSTR::operator==(const char *s) const{ return compare(s)==0; };
- int _SUBSTR::operator<=(const char *s) const{ return compare(s)<=0; };
- int _SUBSTR::operator>=(const char *s) const{ return compare(s)>=0; };
- int _SUBSTR::operator!=(const char *s) const{ return compare(s)!=0; };
- int _SUBSTR::operator< (const char *s) const{ return compare(s)< 0; };
- int _SUBSTR::operator> (const char *s) const{ return compare(s)> 0; };
-
- int _SUBSTR::operator==(const substr& s) const{ return compare(s)==0; };
- int _SUBSTR::operator<=(const substr& s) const{ return compare(s)<=0; };
- int _SUBSTR::operator>=(const substr& s) const{ return compare(s)>=0; };
- int _SUBSTR::operator!=(const substr& s) const{ return compare(s)!=0; };
- int _SUBSTR::operator< (const substr& s) const{ return compare(s)< 0; };
- int _SUBSTR::operator> (const substr& s) const{ return compare(s)> 0; };
-
- _SUBSTR::operator str() const{
- str temp;
- temp.assign((*(mystr))(posReplace), numReplace);
- return temp;
- };
-
- int str::_checkMemAllocation(int requiredLen){
- if ((data->refcount<=1) && (size()>=requiredLen)) return 1;
-
- return (getNewBuffer(max(size(), requiredLen))!=NULL);
- };
-
-
- //
- // Case sensitivity member functions
- //
- int str::caseSensitive(void) const { return !(flags & ICASE); }
-
- void str::setCaseSensitive(int val)
- {
- if (val) flags &= !ICASE;
- else flags |= ICASE;
- }
-
- void str::setdefaultCaseSensitive(int val)
- {
- if (val) defaultFlags &= !ICASE;
- else defaultFlags |= ICASE;
- }
-
- //
- // Friend/Global str relational operators
- //
- str operator + (const char *a, const str&b) { return str(a,b); };
- str operator + (const char *a, const _SUBSTR&b){ return str(a,b); };
-
- int compare(const char * a, const str & b) {return ( b.strcmp(a, b) );};
- int compare(const str& a, const str & b) {return ( a.strcmp(a, b) );};
- int compare(const str& a, const char * b) {return ( a.strcmp(a, b) );};
-
- int operator ==(const char *a, const str&b){return (compare(a,b) == 0); };
- int operator >=(const char *a, const str&b){return (compare(a,b) >= 0); };
- int operator <=(const char *a, const str&b){return (compare(a,b) <= 0); };
- int operator !=(const char *a, const str&b){return (compare(a,b) != 0); };
- int operator > (const char *a, const str&b){return (compare(a,b) > 0); };
- int operator < (const char *a, const str&b){return (compare(a,b) < 0);};
-
- int operator ==(const char *a, const _SUBSTR &b){ return b==a; };
- int operator >=(const char *a, const _SUBSTR &b){ return b<=a; };
- int operator <=(const char *a, const _SUBSTR &b){ return b>=a; };
- int operator !=(const char *a, const _SUBSTR &b){ return b!=a; };
- int operator > (const char *a, const _SUBSTR &b){ return b<a; };
- int operator < (const char *a, const _SUBSTR &b){ return b>a; };
-
- //
- // Member str relational operators
- //
- int str::operator==(const char *b) const{ return (compare(*this,b) == 0); };
- int str::operator<=(const char *b) const{ return (compare(*this,b) <= 0); };
- int str::operator>=(const char *b) const{ return (compare(*this,b) >= 0); };
- int str::operator!=(const char *b) const{ return (compare(*this,b) != 0); };
- int str::operator> (const char *b) const{ return (compare(*this,b) > 0); };
- int str::operator< (const char *b) const{ return (compare(*this,b) < 0); };
-
- int str::operator==(const str &b) const{ return (compare(*this,b) == 0); };
- int str::operator<=(const str &b) const{ return (compare(*this,b) <= 0); };
- int str::operator>=(const str &b) const{ return (compare(*this,b) >= 0); };
- int str::operator!=(const str &b) const{ return (compare(*this,b) != 0); };
- int str::operator> (const str &b) const{ return (compare(*this,b) > 0); };
- int str::operator< (const str &b) const{ return (compare(*this,b) < 0); };
-
-
- int str::strncmp(const char * s1, const char * s2, int n) const{
- if (caseSensitive()) return ::strncmp(s1,s2,n);
- else return ::strnicmp(s1,s2,n);
- };
-
- int str::strcmp(const char * s1, const char * s2) const{
- if (caseSensitive()) return ::strcmp(s1,s2);
- else return ::stricmp(s1,s2);
- };
-
- int str::defaultFlags = 0;
-
- #ifdef DEBUG_STR
- int str::dynstreamCount=0;
- int str::ObjectCount=0;
- int str::AllocationCount=0;
- int str::TotalObjectCount=0;
- int str::TotalAllocationCount=0;
- #endif
-